home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacHack 1997
/
MacHack 1997.toast
/
Hacks
/
Hacks ’94
/
[√] Distribution Restricted!
/
Christian Ruse
/
Fourier Paper + Apps
/
nih-image154_source.sea
/
V1.54 Source
/
Functions.p
< prev
next >
Wrap
Text File
|
1993-10-14
|
50KB
|
1,896 lines
unit Functions;
{}
interface
uses
QuickDraw, Palettes, PrintTraps, globals, Utilities, Graphics, File1, File2, Analysis, Camera, Lut;
procedure ApplyTable (var table: LookupTable);
procedure ApplyLookupTable;
procedure MakeBinary;
procedure Filter (ftype: FilterType; pass: integer; var table: FateTable);
procedure PhotoMode;
function AllSameSize: boolean;
procedure EnhanceContrast;
procedure EqualizeHistogram;
procedure Convolve (name: str255; RefNum: integer);
procedure ConvolveUsingText;
procedure PlotSurface;
procedure MakeSkeleton;
procedure DoErosion;
procedure DoDilation;
procedure DoOpening;
procedure DoClosing;
procedure SetBinaryCount;
procedure SetIterations;
procedure ChangeValues (v1, v2, v3: integer);
procedure DoPropagate (MenuItem: integer);
procedure DoArithmetic (MenuItem: integer; constant: extended);
procedure NewPlotSurface;
procedure AutoThreshold;
procedure AutoDensitySlice;
procedure FixColors;
procedure DoImageMath;
implementation
const
MaxW = 4000;
Src1Item = 7;
Src2Item = 8;
OpItem = 9;
type
ktype = array[0..MaxW] of integer;
SortArray = array[1..9] of integer;
var
PixelsRemoved: LongInt;
Src1PicNum, Src2PicNum: integer;
procedure ApplyTableToLine (data: ptr; var table: LookupTable; width: LongInt);
{$IFC false}
var
line: LinePtr;
i: integer;
begin
line := LinePtr(data);
for i := 0 to width - 1 do
Line^[i] := table[Line^[i]];
end;
{$ENDC}
{a0 = data}
{a1 = lookup table}
{d0 = width }
{d1 = pixel value}
inline
$4E56, $0000, { link a6,#0}
$48E7, $C0C0, { movem.l a0-a1/d0-d1,-(sp)}
$206E, $000C, { move.l 12(a6),a0}
$226E, $0008, { move.l 8(a6),a1}
$202E, $0004, { move.l 4(a6),d0}
$5380, { subq.l #1,d0}
$4281, { clr.l d1}
$1210, {L move.b (a0),d1}
$10F1, $1000, { move.b 0(a1,d1.w),(a0)+}
$51C8, $FFF8, { dbra d0,L}
$4CDF, $0303, { movem.l (sp)+,a0-a1/d0-d1}
$4E5E, { unlk a6}
$DEFC, $000C; { add.w #12,sp}
procedure PutLineUsingMask (h, v, count: integer; var line: LineType);
var
aLine, MaskLine: LineType;
i: integer;
SaveInfo: InfoPtr;
begin
if count > MaxLine then
count := MaxLine;
GetLine(h, v, count, aline);
SaveInfo := Info;
Info := UndoInfo;
GetLine(h, v, count, MaskLine);
for i := 0 to count - 1 do
if MaskLine[i] = BlackIndex then
aLine[i] := line[i];
info := SaveInfo;
PutLine(h, v, count, aLine);
end;
procedure ApplyTable; {(var table: LookupTable)}
var
width, NumberOfLines, i, hloc, vloc: integer;
offset: LongInt;
p: ptr;
UseMask: boolean;
TempLine: LineType;
AutoSelectAll: boolean;
begin
if NotInBounds then
exit(ApplyTable);
StopDigitizing;
AutoSelectAll := not Info^.RoiShowing;
if AutoSelectAll then
SelectAll(false);
if TooWide then
exit(ApplyTable);
ShowWatch;
with info^.RoiRect, info^ do begin
if RoiType <> RectRoi then
UseMask := SetupMask
else
UseMask := false;
SetupUndoFromClip;
WhatToUndo := UndoTransform;
offset := LongInt(top) * BytesPerRow + left;
if UseMask then
p := @TempLine
else
p := ptr(ord4(PicBaseAddr) + offset);
width := right - left;
NumberOfLines := bottom - top;
hloc := left;
vloc := top;
end;
if width > 0 then
for i := 1 to NumberOfLines do
if UseMask then begin
GetLine(hloc, vloc, width, TempLine);
ApplyTableToLine(p, table, width);
PutLineUsingMask(hloc, vloc, width, TempLine);
vloc := vloc + 1
end
else begin
ApplyTableToLine(p, table, width);
p := ptr(ord4(p) + info^.BytesPerRow);
end;
with info^ do begin
UpdateScreen(RoiRect);
Info^.changes := true;
end;
SetupRoiRect;
if AutoSelectAll then
KillRoi;
end;
function DoApplyTableDialogBox: boolean;
const
Button1 = 3;
Button2 = 4;
Button3 = 5;
Button4 = 6;
var
mylog: DialogPtr;
item: integer;
SaveA, SaveB: boolean;
procedure SetButtons;
begin
SetDialogItem(mylog, Button1, ord(ThresholdToForeground));
SetDialogItem(mylog, Button2, ord(not ThresholdToForeground));
SetDialogItem(mylog, Button3, ord(NonThresholdToBackground));
SetDialogItem(mylog, Button4, ord(not NonThresholdToBackground));
end;
begin
InitCursor;
SaveA := ThresholdToForeground;
SaveB := NonThresholdToBackground;
mylog := GetNewDialog(40, nil, pointer(-1));
SetButtons;
OutlineButton(MyLog, ok, 16);
repeat
ModalDialog(nil, item);
if (item = Button1) or (item = button2) then begin
ThresholdToForeground := not ThresholdToForeground;
SetButtons;
end;
if (item = Button3) or (item = button4) then begin
NonThresholdToBackground := not NonThresholdToBackground;
SetButtons;
end;
until (item = ok) or (item = cancel);
DisposDialog(mylog);
if item = cancel then begin
ThresholdToForeground := SaveA;
NonThresholdToBackground := SaveB;
DoApplyTableDialogBox := false
end
else
DoApplyTableDialogBox := true;
end;
procedure ApplyLookupTable;
var
table: LookupTable;
ConvertingColorPic, GrayScaleImage: boolean;
i: integer;
begin
with info^ do begin
GrayScaleImage := (LUTMode = Grayscale) or (LUTMode = CustomGrayscale);
ConvertingColorPic := not GrayScaleImage and not DensitySlicing;
if ConvertingColorPic then
KillRoi;
if DensitySlicing and (not macro) then begin
if not DoApplyTableDialogBox then
exit(ApplyLookupTable);
end;
if thresholding then
BinaryPic := true;
GetLookupTable(table);
if GrayscaleImage or ConvertingColorPic then
ResetGrayMap;
ApplyTable(table);
if ConvertingColorPic then
WhatToUndo := NothingToUndo;
if DensityCalibrated then begin
DensityCalibrated := false;
for i := 0 to 255 do
cvalue[i] := i;
end;
end; {with}
end;
procedure MakeBinary;
var
table: LookupTable;
SaveBackground, SaveForeground, i: integer;
begin
with info^ do begin
if DensitySlicing then begin
ThresholdToForeground := true;
NonThresholdToBackground := true;
SaveBackground := BackgroundIndex;
SaveForeground := ForegroundIndex;
BackgroundIndex := WhiteIndex;
ForegroundIndex := BlackIndex;
GetLookupTable(table);
ResetGrayMap;
ApplyTable(table);
BackgroundIndex := SaveBackground;
ForegroundIndex := SaveForeground;
BinaryPic := true;
end
else if Thresholding then begin
for i := 0 to 255 do
if i < ColorStart then
table[i] := WhiteIndex
else
table[i] := BlackIndex;
ResetGrayMap;
ApplyTable(table);
BinaryPic := true;
end
else
PutMessage('Sorry, but you must be thresholding or density slicing to use Make Binary.');
end;
end;
{$IFC false}
function FindMedian (var a: SortArray): integer;
{Finds the 5th largest of 9 values}
var
i, j, mj, max: integer;
begin
for i := 1 to 4 do begin
max := 0;
mj := 1;
for j := 1 to 9 do
if a[j] > max then begin
max := a[j];
mj := j;
end;
a[mj] := 0;
end;
max := 0;
for j := 1 to 9 do
if a[j] > max then
max := a[j];
FindMedian := max;
end;
{$ENDC}
function FindMedian (var a: sortArray): integer;
{In-line code contributed by Edward J. Huff(huff@mcclbo.med.nyu.edu).}
{Assember source with comments and a test program are available by anonymous}
{ftp from zippy.nimh.nih.gov, in the /pub/nih-image/documents directory.}
inline
$205F, $48E7, $1F00, $4C98, $00FF, $B041, $6502, $C340,{}
$B443, $6502, $C742, $B243, $6504, $C540, $C741, $B845,{}
$6502, $CB44, $BC47, $6502, $CF46, $BA47, $6504, $CD44,{}
$CF45, $B245, $6508, $CF43, $CD42, $CB41, $C940, $3E10,{}
$BC47, $6502, $CF46, $BA47, $6504, $CD44, $CF45, $B245,{}
$6508, $CF43, $CD42, $CB41, $C940, $B246, $6534, $B242,{}
$6514, $B244, $6504, $3001, $6062, $B644, $6504, $3004,{}
$605A, $3003, $6056, $B444, $650C, $B445, $6504, $3005,{}
$604A, $3002, $6046, $B644, $6504, $3004, $603E, $3003,{}
$603A, $B645, $6504, $C942, $CB43, $B846, $651C, $B644,{}
$650C, $B444, $6504, $3002, $6022, $3004, $601E, $B646,{}
$6504, $3003, $6016, $3006, $6012, $B646, $6508, $B446,{}
$65F4, $3002, $6006, $B644, $65E0, $3003, $4CDF, $00F8,{}
$3E80;
procedure Filter (ftype: FilterType; pass: integer; var table: FateTable);
const
PixelsPerUpdate = 5000;
var
row, width, r1, r2, r3, c, value, error, sum, center: integer;
tmp, mark, NewMark, LinesPerUpdate, LineCount: integer;
t1, t2, t3, t4: integer;
MaskRect, frame, trect: rect;
WhitePixel1: integer;
L1: LineType;
WhitePixel2: integer;
L2: LineType;
WhitePixel3: integer;
L3, result: LineType;
pt: point;
a: SortArray;
AutoSelectAll, UseMask, BinaryFilter: boolean;
L, T, R, B, index, code, FirstRow, LastRow: integer;
StartTicks: LongInt;
begin
if NotinBounds then
exit(Filter);
StopDigitizing;
AutoSelectAll := not Info^.RoiShowing;
if AutoSelectAll then
with info^ do begin
SelectAll(false);
SetPort(wptr);
PenNormal;
PenPat(pat[PatIndex]);
FrameRect(wrect);
end;
if TooWide then
exit(Filter);
ShowWatch;
if info^.RoiType <> RectRoi then
UseMask := SetupMask
else
UseMask := false;
if pass = 0 then begin
SetupUndoFromClip;
ShowMessage(CmdPeriodToStop);
WhatToUndo := UndoFilter;
end;
frame := info^.RoiRect;
StartTicks := TickCount;
BinaryFilter := ftype in [Erosion, Dilation, OutlineFilter, Skeletonize];
with frame, Info^ do begin
changes := true;
RoiShowing := false;
width := right - left;
LinesPerUpdate := PixelsPerUpdate div width;
if ftype = ReduceNoise then
LinesPerUpdate := LinesPerUpdate div 3;
if BinaryFilter then begin
FirstRow := top;
LastRow := bottom - 1;
WhitePixel1 := WhiteIndex;
WhitePixel2 := WhiteIndex;
WhitePixel3 := WhiteIndex;
if width < MaxLine then begin
L1[width] := WhiteIndex;
L2[width] := WhiteIndex;
L3[width] := WhiteIndex;
end;
end
else begin
FirstRow := top + 1;
LastRow := bottom - 2;
end;
GetLine(left, FirstRow - 1, width, L2);
GetLine(left, FirstRow, width, L3);
Mark := RoiRect.top;
LineCount := 0;
for row := FirstRow to LastRow do begin
{Move Convolution Window Down}
BlockMove(@L2, @L1, width);
BlockMove(@L3, @L2, width);
GetLine(left, row + 1, width, L3);
{Process One Row}
case ftype of
EdgeDetect:
for c := 1 to width - 2 do begin
t1 := L1[c - 1] + L1[c] + L1[c + 1] - L3[c - 1] - L3[c] - L3[c + 1];
t1 := abs(t1);
t2 := L1[c + 1] + L2[c + 1] + L3[c + 1] - L1[c - 1] - L2[c - 1] - L3[c - 1];
t2 := abs(t2);
if t1 > t2 then
tmp := t1
else
tmp := t2;
if OptionKeyWasDown then begin
if tmp > 255 then
tmp := 255;
if tmp < 0 then
tmp := 0;
end
else if tmp > 35 then
tmp := 255
else
tmp := 0;
result[c] := tmp;
end;
ReduceNoise: {Median Filter}
for c := 1 to width - 2 do begin
a[1] := L1[c - 1];
a[2] := L1[c];
a[3] := L1[c + 1];
a[4] := L2[c - 1];
a[5] := L2[c];
a[6] := L2[c + 1];
a[7] := L3[c - 1];
a[8] := L3[c];
a[9] := L3[c + 1];
result[c] := FindMedian(a);
end;
Dither: {Floyd-Steinberg Algorithm}
for c := 1 to width - 2 do begin
value := L2[c];
if value < 128 then begin
result[c] := 0;
error := -value;
end
else begin
result[c] := 255;
error := 255 - value
end;
tmp := L2[c + 1]; {A}
tmp := tmp - (7 * error) div 16;
if tmp < 0 then
tmp := 0;
if tmp > 255 then
tmp := 255;
L2[c + 1] := tmp;
tmp := L3[c + 1]; {B}
tmp := tmp - error div 16;
if tmp < 0 then
tmp := 0;
if tmp > 255 then
tmp := 255;
L3[c + 1] := tmp;
tmp := L3[c]; {C}
tmp := tmp - (5 * error) div 16;
if tmp < 0 then
tmp := 0;
if tmp > 255 then
tmp := 255;
L3[c] := tmp;
tmp := L3[C - 1]; {D}
tmp := tmp - (3 * error) div 16;
if tmp < 0 then
tmp := 0;
if tmp > 255 then
tmp := 255;
L3[C - 1] := tmp;
end;
UnweightedAvg:
for c := 1 to width - 2 do begin
tmp := (L1[C - 1] + L1[c] + L1[c + 1] + L2[c - 1] + L2[c] + L2[c + 1] + L3[c - 1] + L3[c] + L3[c + 1]) div 9;
if tmp > 255 then
tmp := 255;
if tmp < 0 then
tmp := 0;
result[c] := tmp;
end;
WeightedAvg:
for c := 1 to width - 2 do begin
tmp := (L1[c - 1] + L1[c] + L1[c + 1] + L2[c - 1] + L2[c] * 4 + L2[c + 1] + L3[c - 1] + L3[c] + L3[c + 1]) div 12;
if tmp > 255 then
tmp := 255;
if tmp < 0 then
tmp := 0;
result[c] := tmp;
end;
fsharpen:
for c := 1 to width - 2 do begin
if OptionKeyWasDown then
tmp := L2[c] * 9 - L1[c - 1] - L1[c] - L1[c + 1] - L2[c - 1] - L2[c + 1] - L3[c - 1] - L3[c] - L3[c + 1]
else begin
tmp := L2[c] * 12 - L1[c - 1] - L1[c] - L1[c + 1] - L2[c - 1] - L2[c + 1] - L3[c - 1] - L3[c] - L3[c + 1];
tmp := tmp div 4;
end;
if tmp > 255 then
tmp := 255;
if tmp < 0 then
tmp := 0;
result[c] := tmp;
end;
fshadow:
for c := 1 to width - 2 do begin
tmp := L2[c + 1] + L2[c + 1] + L3[c] + L3[c + 1] * 2 - L1[c - 1] * 2 - L1[c] - L2[c - 1];
if tmp > 255 then
tmp := 255;
if tmp < 0 then
tmp := 0;
result[c] := tmp;
end;
Erosion:
for c := 0 to width - 1 do begin
center := L2[c];
if center = BlackIndex then begin
sum := L1[c - 1] + L1[c] + L1[c + 1] + L2[c - 1] + L2[c + 1] + L3[c - 1] + L3[c] + L3[c + 1];
if (2040 - sum) >= BinaryThreshold then
center := WhiteIndex;
end;
result[c] := center;
end;
Dilation:
for c := 0 to width - 1 do begin
center := L2[c];
if center = WhiteIndex then begin
sum := L1[c - 1] + L1[c] + L1[c + 1] + L2[c - 1] + L2[c + 1] + L3[c - 1] + L3[c] + L3[c + 1];
if sum >= BinaryThreshold then
center := BlackIndex;
end;
result[c] := center;
end;
OutlineFilter:
for c := 0 to width - 1 do begin
center := L2[c];
if center = BlackIndex then begin
if (L2[c - 1] = WhiteIndex) or (L1[c] = WhiteIndex) or (L2[c + 1] = WhiteIndex) or (L3[c] = WhiteIndex) then
center := BlackIndex
else
center := WhiteIndex;
end;
result[c] := center;
end;
Skeletonize:
for c := 0 to width - 1 do begin
center := L2[c];
if center = BlackIndex then begin
index := 0;
if L1[c - 1] = BlackIndex then
index := bor(index, 1);
if L1[c] = BlackIndex then
index := bor(index, 2);
if L1[c + 1] = BlackIndex then
index := bor(index, 4);
if L2[c + 1] = BlackIndex then
index := bor(index, 8);
if L3[c + 1] = BlackIndex then
index := bor(index, 16);
if L3[c] = BlackIndex then
index := bor(index, 32);
if L3[c - 1] = BlackIndex then
index := bor(index, 64);
if L2[c - 1] = BlackIndex then
index := bor(index, 128);
code := table[index];
if odd(pass) then begin
if (code = 2) or (code = 3) then begin
center := WhiteIndex;
PixelsRemoved := PixelsRemoved + 1;
end;
end
else begin {even pass}
if (code = 1) or (code = 3) then begin
center := WhiteIndex;
PixelsRemoved := PixelsRemoved + 1;
end;
end;
end; {if}
result[c] := center;
end; {for}
end; {case}
if not BinaryFilter then begin
result[0] := L2[0];
result[width - 1] := L2[width - 1];
end;
if UseMask then
PutLineUsingMask(left, row, width, result)
else
PutLine(left, row, width, result);
LineCount := LineCount + 1;
if LineCount = LinesPerUpdate then begin
pt.h := RoiRect.left;
pt.v := row + 1;
NewMark := pt.v;
with RoiRect do
SetRect(MaskRect, left, mark, right, NewMark);
UpdateScreen(MaskRect);
LineCount := 0;
Mark := NewMark;
if magnification > 1.0 then
Mark := Mark - 1;
if CommandPeriod then begin
UpdatePicWindow;
beep;
PixelsRemoved := 0;
if AutoSelectAll then
KillRoi;
exit(filter)
end;
end;
end; {for row:=...}
trect := frame;
InsetRect(trect, 1, 1);
ShowTime(StartTicks, trect, '');
end; {with}
if LineCount > 0 then begin
with frame do
SetRect(MaskRect, left, mark, right, bottom);
UpdateScreen(MaskRect)
end;
SetupRoiRect;
if AutoSelectAll then
KillRoi;
end;
procedure PhotoMode;
{Erases the screen to the background color and then redraws}
{the contents of the active image window . }
var
tPort: GrafPtr;
event: EventRecord;
WinRect: rect;
SaveVisRgn: rgnHandle;
begin
with info^ do begin
KillRoi;
if OptionKeyWasDown then begin {Move window up to top of screen.}
GetWindowRect(wptr, WinRect);
MoveWindow(wptr, WinRect.left, 0, false);
end;
with wptr^ do begin
SaveVisRgn := visRgn;
visRgn := NewRgn;
RectRgn(visRgn, ScreenBits.Bounds);
end;
FlushEvents(EveryEvent, 0);
GetPort(tPort);
EraseScreen;
UpdatePicWindow;
repeat
until WaitNextEvent(mDownMask + KeyDownMask, Event, 5, nil);
with wptr^ do begin
DisposeRgn(visRgn);
visRgn := SaveVisRgn;
end;
RestoreScreen;
SetPort(tPort);
FlushEvents(EveryEvent, 0);
if OptionKeyWasDown then begin
MoveWindow(wptr, WinRect.left, WinRect.top, false);
end;
end;
end;
function AllSameSize: boolean;
{Returns true if all currently open Images have the same dimensions.}
var
i: integer;
SameSize: Boolean;
TempInfo: InfoPtr;
begin
if nPics = 0 then begin
AllSameSize := false;
exit(AllSameSize);
end;
SameSize := true;
for i := 1 to nPics do begin
TempInfo := pointer(WindowPeek(PicWindow[i])^.RefCon);
SameSize := SameSize and EqualRect(Info^.PicRect, TempInfo^.PicRect);
end;
AllSameSize := SameSize;
end;
procedure EnhanceContrast;
var
AutoSelectAll: boolean;
min, max, i, threshold: integer;
found, SaveRedirectFlag: boolean;
sum: LongInt;
begin
with info^ do
if LUTMode = ColorLUT then begin
PutMessage('Sorry, but you can not contrast enhance true color images.');
exit(EnhanceContrast)
end;
if NotInBounds or (ClipBuf = nil) then
exit(EnhanceContrast);
StopDigitizing;
AutoSelectAll := not Info^.RoiShowing;
if AutoSelectAll then
SelectAll(false);
SaveRedirectFlag := RedirectSampling;
RedirectSampling := false;
if info^.RoiType = RectRoi then
GetRectHistogram
else
GetHistogram;
RedirectSampling := SaveRedirectFlag;
sum := 0;
for i := 0 to 255 do
sum := sum + histogram[i];
threshold := sum div 5000;
i := -1;
repeat
i := i + 1;
found := histogram[i] > threshold;
until found or (i = 255);
min := i;
i := 256;
repeat
i := i - 1;
found := histogram[i] > threshold;
until found or (i = 0);
max := i;
if max > min then
with info^ do begin
SetupLutUndo;
if isGrayScaleLUT then
LUTMode := grayscale;
ColorStart := min;
ColorEnd := max;
DrawMap;
UpdateLUT;
changes := true;
IdentityFunction := false;
end;
if AutoSelectAll then
KillRoi;
end;
procedure EqualizeHistogram;
var
AutoSelectAll, SaveRedirectFlag: boolean;
i, sum, v: integer;
isum: LongInt;
ScaleFactor: extended;
begin
with info^ do
if (LUTMode <> GrayScale) and (LutMode <> CustomGrayscale) then begin
PutMessage('Sorry, but you can only do histogram equalization on grayscale images.');
exit(EqualizeHistogram)
end;
if NotInBounds or (ClipBuf = nil) then
exit(EqualizeHistogram);
StopDigitizing;
AutoSelectAll := not Info^.RoiShowing;
if AutoSelectAll then
SelectAll(false);
SaveRedirectFlag := RedirectSampling;
RedirectSampling := false;
if info^.RoiType = RectRoi then
GetRectHistogram
else
GetHistogram;
RedirectSampling := SaveRedirectFlag;
FindThresholdingMode;
ComputeResults;
isum := 0;
for i := 0 to 255 do
isum := isum + histogram[i];
ScaleFactor := 255.0 / isum;
sum := 0;
with info^ do begin
SetupLutUndo;
for i := 255 downto 0 do
with cTable[i].rgb do begin
sum := round(sum + histogram[i] * ScaleFactor);
if sum > 255 then
sum := 255;
v := sum * 256;
red := v;
green := v;
blue := v;
end;
LoadLUT(cTable);
LUTMode := CustomGrayscale;
SetupPseudocolor;
changes := true;
DrawMap;
IdentityFunction := false;
end; {with info}
if AutoSelectAll then
KillRoi;
end;
procedure GetKernel (var kernel: ktype; var n: integer; var name: str255; RefNum: integer);
var
rLine: rLineType;
i, count, nValues, nRows: integer;
begin
count := 0;
nRows := 0;
InitTextInput(name, RefNum);
while not TextEof and (nRows <= 63) do begin
GetLineFromText(rLine, nValues);
if count <> 0 then
nRows := nRows + 1;
if nRows = 1 then
n := nValues;
for i := 1 to nValues do begin
count := count + 1;
kernel[count - 1] := round(rLine[i]);
end;
end;
if count <> (n * n) then
n := 0;
end;
procedure DoOnePixel (nLess1, BytesPerLine: integer; corner: LongInt; var sum: LongInt; var kernel: ktype);
{$IFC false}
var
row, column, k: integer;
pp: ptr;
begin
k := 0;
sum := 0;
for row := 0 to nless1 do begin
corner := corner + BytesPerLine;
pp := ptr(corner);
for column := 0 to nless1 do begin
sum := sum + band(pp^, 255) * kernel[k];
k := k + 1;
pp := ptr(ord(pp) + 1);
end;
end;
end;
{$ENDC}
{a0=^corner/^sum}
{a1=^kernel}
{a2=^pixels}
{d0=n-1}
{d1=BytesPerLine}
{d2=sum}
{d3=n-1(outer loop)}
{d4=n-1(inner loop)}
{d5=temp}
inline
$4E56, $0000, { link a6,#0}
$48E7, $FCE0, { movem.l a0-a2/d0-d5,-(sp)}
$4280, { clr.l d0}
$302E, $0012, { move.w 18(a6),d0}
$4281, { clr.l d1}
$322E, $0010, { move.w 16(a6),d1}
$206E, $000C, { movea.l 12(a6),a0}
$226E, $0004, { movea.l 4(a6),a1}
$4282, { clr.l d2}
$2600, { move.l d0,d3}
$D1C1, {A adda.l d1,a0}
$2448, { move.l a0,a2}
$2800, { move.l d0,d4}
$4285, {B clr.l d5 (2)}
$1A1A, { move.b (a2)+,d5 (6) }
$CBD9, { muls (a1)+,d5 (29!)}
$D485, { add.l d5,d2 (2)}
$51CC, $FFF6, { dbra d4,B (6)}
$51CB, $FFEC, { dbra d3,A}
$206E, $0008, { move.l 8(a6),a0}
$2082, { move.l d2,(a0)}
$4CDF, $073F, { movem.l (sp)+,a0-a2/d0-d5}
$4E5E, { unlk a6}
$DEFC, $0010; { add.w #16,sp}
procedure DoConvolution (var kernel: ktype; n: integer);
const
skip = 7;
var
row, width, column, value, error: integer;
margin, i, nless1: integer;
frame, MaskRect, tRect: rect;
AutoSelectAll, ScalingNeeded: boolean;
SrcCenter, DstCenter, sum, max, offset, wsum, cscale, StartTicks: LongInt;
MinResult, MaxResult: LongInt;
p: ptr;
str, str2: str255;
ScaleFactor: extended;
begin
if NotinBounds or NotRectangular then
exit(DoConvolution);
StopDigitizing;
AutoSelectAll := not Info^.RoiShowing;
if AutoSelectAll then
SelectAll(false);
SetupUndoFromClip;
WhatToUndo := UndoFilter;
frame := info^.RoiRect;
with frame, Info^ do begin
if ((LutMode = GrayScale) or (LutMode = CustomGrayscale)) and (not IdentityFunction) then
ApplyLookupTable;
changes := true;
margin := n div 2;
if left < margin then
left := left + margin;
if right > (PicRect.right - margin) then
right := right - margin;
if top < margin then
top := top + margin;
if bottom > (PicRect.bottom - margin) then
bottom := bottom - margin;
SetPort(wptr);
PenNormal;
PenPat(pat[PatIndex]);
tRect := frame;
OffscreenToScreenRect(tRect);
FrameRect(tRect);
width := right - left;
max := n * n - 1;
wsum := 0;
for i := 0 to max do
wsum := wsum + kernel[i];
NumToString(n, str);
NumToString(wsum, str2);
ValuesMessage := Concat(str, ' x ', str, ' kernel', cr, 'sum = ', str2, cr, cr, CmdPeriodToStop);
ShowValues;
if wsum <> 0 then
cscale := wsum
else
cscale := 1;
offset := -(n div 2) * BytesPerRow - BytesPerRow - n div 2;
nless1 := n - 1;
StartTicks := TickCount;
str := '';
if ScaleConvolutions then begin
MinResult := MaxLongInt;
MaxResult := -MaxLongInt;
row := top;
while row < bottom do begin
SrcCenter := ord4(ClipBufInfo^.PicBaseAddr) + LongInt(row) * BytesPerRow + left;
column := left;
while column < (left + width) do begin
DoOnePixel(nless1, BytesPerRow, SrcCenter + offset, sum, kernel);
value := sum div cscale;
if value < MinResult then
MinResult := value;
if value > MaxResult then
MaxResult := value;
SrcCenter := SrcCenter + skip;
column := column + skip;
end; {while column}
row := row + skip;
end; {while row...}
ScalingNeeded := (MinResult < 0) or (MaxResult > 255);
if ScalingNeeded then
ScaleFactor := 253.0 / (MaxResult - MinResult)
else
ScaleFactor := 1.0;
RealToString(ScaleFactor, 1, 4, str);
str := concat('min=', long2str(MinResult), cr, 'max=', long2str(MaxResult), cr, 'scale factor= ', str);
for row := top to bottom - 1 do begin
SrcCenter := ord4(ClipBufInfo^.PicBaseAddr) + LongInt(row) * BytesPerRow + left;
DstCenter := ord4(PicBaseAddr) + LongInt(row) * BytesPerRow + left;
for column := left to left + width - 1 do begin
DoOnePixel(nless1, BytesPerRow, SrcCenter + offset, sum, kernel);
value := sum div cscale;
if ScalingNeeded then begin
if value < MinResult then
value := MinResult;
if value > MaxResult then
value := MaxResult;
value := round((value - MinResult) * ScaleFactor + 1);
end;
p := ptr(DstCenter);
p^ := BAND(value, 255);
SrcCenter := SrcCenter + 1;
DstCenter := DstCenter + 1;
end; {for column:=}
SetRect(MaskRect, left, row, right, row + 1);
UpdateScreen(MaskRect);
if CommandPeriod then begin
UpdatePicWindow;
beep;
exit(DoConvolution)
end;
end; {for row:=...}
end {Scale Convolutions}
else
for row := top to bottom - 1 do begin
SrcCenter := ord4(ClipBufInfo^.PicBaseAddr) + LongInt(row) * BytesPerRow + left;
DstCenter := ord4(PicBaseAddr) + LongInt(row) * BytesPerRow + left;
for column := left to left + width - 1 do begin
DoOnePixel(nless1, BytesPerRow, SrcCenter + offset, sum, kernel);
value := sum div cscale;
if value < MinResult then
MinResult := value;
if value > MaxResult then
MaxResult := value;
if value > 255 then
value := 255;
if value < 0 then
value := 0;
p := ptr(DstCenter);
p^ := BAND(value, 255);
SrcCenter := SrcCenter + 1;
DstCenter := DstCenter + 1;
end; {for column:=}
SetRect(MaskRect, left, row, right, row + 1);
UpdateScreen(MaskRect);
if CommandPeriod then begin
UpdatePicWindow;
beep;
exit(DoConvolution)
end;
end; {for row:=...}
ShowTime(StartTicks, frame, str);
end; {with}
UpdatePicWindow;
SetupRoiRect;
if AutoSelectAll then
KillRoi;
end;
procedure Convolve (name: str255; RefNum: integer);
var
kernel: ktype;
n, count: integer;
begin
if name = '' then begin
RefNum := 0;
if not GetTextFile(name, RefNum) then
exit(convolve)
else
KernelsRefNum := RefNum;
end;
DisableDensitySlice;
GetKernel(kernel, n, name, RefNum);
count := n * n;
UpdatePicWindow;
if (n >= 3) and (n <= 63) then
DoConvolution(kernel, n)
else
PutMessage('Kernels must be n x n square matrices with 3 <= n <= 63.');
end;
procedure ConvolveUsingText;
var
f: integer;
err: OSErr;
count: LongInt;
begin
err := fsdelete('TempKernel', SystemRefNum);
err := create('TempKernel', SystemRefNum, 'imag', 'TEXT');
if err = NoErr then
err := fsopen('TempKernel', SystemRefNum, f);
if err <> NoErr then begin
putmessage('Unable to open temporary file.');
exit(ConvolveUsingText);
end;
if TextInfo <> nil then
with TextInfo^ do begin
count := TextTE^^.TELength;
err := fswrite(f, count, TextTE^^.hText^);
err := fsclose(f);
Convolve('TempKernel', SystemRefNum);
err := fsdelete('TempKernel', SystemRefNum);
end;
end;
function NewPicWindowD (name: str255): boolean;
const
WidthID = 5;
HeightID = 6;
TitleID = 8;
var
mylog: DialogPtr;
item: integer;
SaveWidth, SaveHeight: integer;
okay: boolean;
begin
if not macro and not OptionKeyWasDown then begin
InitCursor;
SaveWidth := NewPicWidth;
SaveHeight := NewPicHeight;
mylog := GetNewDialog(190, nil, pointer(-1));
SetDNum(MyLog, WidthID, NewPicWidth);
SelIText(MyLog, WidthID, 0, 32767);
SetDNum(MyLog, HeightID, NewPicHeight);
SetDString(MyLog, TitleID, name);
OutlineButton(MyLog, ok, 16);
repeat
ModalDialog(nil, item);
if item = WidthID then begin
NewPicWidth := GetDNum(MyLog, WidthID);
if (NewPicWidth < 0) or (NewPicWidth > MaxPicSize) then begin
NewPicWidth := SaveWidth;
SetDNum(MyLog, WidthID, NewPicWidth);
end;
end;
if item = HeightID then begin
NewPicHeight := GetDNum(MyLog, HeightID);
if (NewPicHeight < 0) or (NewPicHeight > MaxPicSize) then begin
NewPicHeight := SaveHeight;
SetDNum(MyLog, HeightID, NewPicHeight);
end;
end;
until (item = ok) or (item = cancel);
if item = ok then
name := GetDString(MyLog, TitleID);
DisposDialog(mylog);
if NewPicWidth < 32 then
NewPicWidth := 32;
if odd(NewPicWidth) then
NewPicWidth := NewPicWidth + 1;
if NewPicHeight < 16 then
NewPicHeight := 16;
if item = cancel then begin
NewPicWidth := SaveWidth;
NewPicHeight := SaveHeight;
exit(NewPicWindowD);
end;
end; {if not macro}
NewPicWindowD := NewPicWindow(name, NewPicWidth, NewPicHeight);
end;
procedure PlotSurface;
var
hend, vend, h, v, DataWidth, DataHeight, i: integer;
htemp, vtemp, ivalue: integer;
skip, DataLeft, DataRight, DataTop, DataBottom: integer;
hLoc, vLoc, hMin, hMax, vMin, vMax, MinIValue, MaxIValue: integer;
hstart, vstart, dh, dv, hbase, vbase, vscale, nPlotLines, CalValue: extended;
peak, MaxPeak, hinc, vinc, nLines, MinCValue, MaxCValue: extended;
poly: PolyHandle;
SaveInfo, PlotInfo: InfoPtr;
aLine: LineType;
MaskRect: rect;
AutoSelectAll, ApplyLUT: boolean;
table: LookupTable;
StartTicks: LongInt;
procedure FindVinc;
begin
with PlotInfo^.PicRect do begin
vstart := 5.0 + MaxPeak - dv * DataWidth;
skip := round(DataHeight / ((bottom - vstart - 5.0) / vinc));
if skip = 0 then
skip := 1;
nPlotLines := DataHeight / skip;
vinc := (bottom - vstart - 5.0) / nPlotLines;
vinc := vinc / 0.95;
repeat
vinc := vinc * 0.95;
hinc := vinc / 2.0;
until (5.0 + hinc * nPlotLines + dh * DataWidth) < right;
end;
end;
begin
if NotRectangular or NotInBounds then
exit(PlotSurface);
StopDigitizing;
DisableDensitySlice;
SetForegroundColor(BlackIndex);
SetBackgroundColor(WhiteIndex);
SaveInfo := Info;
if not NewPicWindowD('Surface Plot') then begin
KillRoi;
exit(PlotSurface)
end;
PlotInfo := info;
info := SaveInfo;
AutoSelectAll := not Info^.RoiShowing;
ShowWatch;
if AutoSelectAll then
SelectAll(true);
if TooWide then
exit(PlotSurface);
with info^ do
ApplyLUT := ((LutMode = GrayScale) or (LutMode = CustomGrayscale)) and (not IdentityFunction);
if ApplyLUT then
GetLookupTable(table);
Measure;
UndoLastMeasurement(true);
with results do begin
MinIValue := MinIndex;
MaxIValue := MaxIndex;
end;
if ApplyLut then begin
MinIvalue := table[MinIValue];
MaxIvalue := table[MaxIValue];
end;
MinCValue := 10e100;
MaxCValue := -10e100;
for i := MinIValue to MaxIValue do begin
ivalue := i;
if ApplyLUT then
ivalue := table[ivalue];
calValue := cvalue[i];
if calValue < minCValue then
minCValue := calValue;
if calValue > maxCValue then
maxCValue := calValue;
end;
WhatToUndo := NothingToUndo;
with results do
if (MaxValue - MinValue) <> 0.0 then
vscale := (255.0 / (MaxValue - MinValue)) * 0.5
else
vscale := 0.5;
with info^.RoiRect do begin
DataLeft := left;
DataRight := right;
DataTop := top;
DataBottom := bottom;
DataWidth := DataRight - DataLeft;
DataHeight := DataBottom - DataTop;
end;
dh := (0.65 * PlotInfo^.PicRect.right) / DataWidth;
dv := -0.4 * dh;
hstart := 5.0;
vinc := 2.0;
MaxPeak := (MaxCValue - MinCValue) * vscale * 0.5;
FindVinc; {First estimate}
MaxPeak := MaxPeak * 2.0;
hmin := DataRight + round(MaxPeak / dv);
if hmin < 0 then
hmin := 0;
vmax := DataTop + round(MaxPeak / vinc);
if vmax > DataBottom then
vmax := DataBottom;
MaxPeak := 0.0;
vloc := DataTop;
skip := 3;
repeat
hloc := hmin;
repeat
ivalue := MyGetPixel(hloc, vloc);
if ApplyLUT then
ivalue := table[ivalue];
calValue := cvalue[ivalue];
peak := (calValue - MinCValue) * vscale + (DataRight - hloc) * dv - (vloc - DataTop) * vinc;
if peak > MaxPeak then
MaxPeak := peak;
hloc := hloc + skip;
until hloc > DataRight;
vloc := vloc + skip;
until vloc > vmax;
FindVinc;
v := DataTop;
StartTicks := TickCount;
SetPort(GrafPtr(PlotInfo^.osPort));
PenNormal;
repeat
hmax := 0;
vmin := 9999;
poly := OpenPoly;
hbase := hstart;
vbase := vstart;
Info := SaveInfo;
GetLine(DataLeft, v, DataWidth, aLine);
info := PlotInfo;
if ApplyLUT then
ApplyTableToLine(@aLine, table, DataWidth);
MoveTo(round(hbase), round(vbase - vscale * (cvalue[aLine[0]] - MinCValue)));
for i := 0 to DataWidth - 1 do begin
hbase := hbase + dh;
vbase := vbase + dv;
hLoc := round(hbase);
vLoc := round(vbase - vscale * (cvalue[aLine[i]] - MinCValue));
LineTo(hloc, vloc);
if hloc > hmax then
hmax := hloc;
if vloc < vmin then
vmin := vloc;
end;
LineTo(round(hbase), round(vbase));
LineTo(round(hstart), round(vstart));
LineTo(round(hstart), round(vstart - vscale * (cvalue[aLine[0]] - MinCValue)));
hmin := round(hstart);
vmax := round(vstart);
ClosePoly;
ErasePoly(poly);
FramePoly(poly);
KillPoly(poly);
SetRect(MaskRect, hmin, vmin, hmax, vmax);
UpdateScreen(MaskRect);
hstart := hstart + hinc;
vstart := vstart + vinc;
v := v + skip;
until (v >= DataBottom) or CommandPeriod;
ShowTime(StartTicks, SaveInfo^.RoiRect, '');
if CommandPeriod then
beep;
info^.changes := true;
end;
procedure MakeSkeleton;
{This table-driven parallel thinning routine is based on an algorithm}
{by Zhang and Suen(CACM, March 1984, 236-239). There is}
{an entry in the table for each of the 256 possible 3x3 neighborhood}
{configurations. An entry of '1' means delete pixel on first pass, '2' means}
{delete pixel on second pass, and '3' means delete on either pass. There is a}
{routine in 'user.p' that will draw all 256 neighborhoods.}
const
s999 = '01234567890123456789012345678901';
s000 = '00030033003130330000000030203033';
s032 = '00000000300000003000000030003022';
s064 = '00000000000000000000000000000000';
s096 = '30000000200020003000000030003020';
s128 = '03330013000000010000000000000001';
s160 = '31000000000000002000000000000000';
s192 = '33130013000000010000000000000000';
s224 = '3301000100000000330100002200200';
var
table: FateTable;
s: str255;
i, pass: integer;
begin
s := concat(s000, s032, s064, s096, s128, s160, s192, s224);
for i := 0 to 254 do
table[i] := ord(s[i + 1]) - ord('0');
table[255] := 0;
pass := 0;
repeat
PixelsRemoved := 0;
filter(skeletonize, pass, table);
pass := pass + 1;
if not CommandPeriod then
filter(skeletonize, pass, table);
pass := pass + 1;
until (PixelsRemoved = 0) or CommandPeriod;
end;
procedure DoErosion;
var
i: integer;
t: FateTable;
begin
for i := 0 to BinaryIterations - 1 do begin
filter(Erosion, i, t);
if CommandPeriod then
leave;
end;
end;
procedure DoDilation;
var
i: integer;
t: FateTable;
begin
for i := 0 to BinaryIterations - 1 do begin
filter(Dilation, i, t);
if CommandPeriod then
leave;
end;
end;
procedure DoOpening;
var
i: integer;
t: FateTable;
begin
for i := 0 to BinaryIterations - 1 do begin
filter(Erosion, i, t);
if CommandPeriod then
exit(DoOpening);
end;
for i := 0 to BinaryIterations - 1 do begin
filter(Dilation, i + BinaryIterations, t);
if CommandPeriod then
exit(DoOpening);
end;
end;
procedure DoClosing;
var
i: integer;
t: FateTable;
begin
for i := 0 to BinaryIterations - 1 do begin
filter(Dilation, i, t);
if CommandPeriod then
exit(DoClosing);
end;
for i := 0 to BinaryIterations - 1 do begin
filter(Erosion, i + BinaryIterations, t);
if CommandPeriod then
exit(DoClosing);
end;
end;
procedure SetBinaryCount;
var
TempCount: integer;
Canceled: boolean;
begin
TempCount := GetInt('Neighborhood Pixel Count(1-8):', BinaryCount, Canceled);
if Canceled then
exit(SetBinaryCount);
if (TempCount >= 1) and (TempCount <= 8) then begin
BinaryCount := TempCount;
BinaryThreshold := BinaryCount * 255
end
else
beep;
end;
procedure SetIterations;
var
TempIterations: integer;
Canceled: boolean;
begin
TempIterations := GetInt('Number of Iterations:', BinaryIterations, Canceled);
if Canceled then
exit(SetIterations);
if (TempIterations >= 1) and (TempIterations < 100) then
BinaryIterations := TempIterations
else
beep;
end;
procedure ChangeValues (v1, v2, v3: integer);
{Changes all pixels in the current selection with a value in the range v1 to v2 to a value of v3.}
var
i, value: integer;
table: LookupTable;
begin
for i := 0 to 255 do begin
value := i;
if (value >= v1) and (value <= v2) then
value := v3;
table[i] := value;
end;
ApplyTable(table);
end;
procedure DoPropagate (MenuItem: integer);
{Copies the current Look-Up Table, spatial calibration, or density calibration to all open windows.}
var
TempInfo: InfoPtr;
i: integer;
procedure CopyLUTInfo;
begin
with info^ do begin
TempInfo^.RedLUT := RedLUT;
TempInfo^.GreenLUT := GreenLUT;
TempInfo^.BlueLUT := BlueLUT;
TempInfo^.ColorStart := ColorStart;
TempInfo^.ColorEnd := ColorEnd;
TempInfo^.nColors := nColors;
TempInfo^.LutMode := LUTMode;
TempInfo^.cTable := cTable;
TempInfo^.FillColor1 := FillColor1;
TempInfo^.FillColor2 := FillColor2;
TempInfo^.FillColor1 := FillColor1;
TempInfo^.SaveFill1 := SaveFill1;
TempInfo^.SaveFill2 := SaveFill2;
end;
end;
procedure CopySpatialCalibration;
var
SaveInfo: InfoPtr;
begin
with info^ do begin
TempInfo^.xSpatialScale := xSpatialScale;
TempInfo^.ySpatialScale := ySpatialScale;
TempInfo^.PixelAspectRatio := PixelAspectRatio;
TempInfo^.RawspatialScale := RawspatialScale;
TempInfo^.ScaleMagnification := ScaleMagnification;
TempInfo^.Units := Units;
TempInfo^.UnitsID := UnitsID;
TempInfo^.FullUnits := FullUnits;
TempInfo^.changes := true;
TempInfo^.SpatiallyCalibrated := SpatiallyCalibrated;
end;
SaveInfo := Info;
Info := TempInfo;
UpdateTitleBar;
Info := SaveInfo;
end;
procedure CopyDensityCalibration;
var
SaveInfo: InfoPtr;
begin
with info^ do begin
TempInfo^.DensityCalibrated := DensityCalibrated;
TempInfo^.ZeroClip := ZeroClip;
TempInfo^.fit := fit;
TempInfo^.nCoefficients := nCoefficients;
TempInfo^.Coefficient := Coefficient;
TempInfo^.UnitOfMeasure := UnitOfMeasure;
TempInfo^.changes := true;
end;
SaveInfo := Info;
Info := TempInfo;
UpdateTitleBar;
Info := SaveInfo;
end;
begin
for i := 1 to nPics do begin
TempInfo := pointer(WindowPeek(PicWindow[i])^.RefCon);
case MenuItem of
1:
CopyLUTInfo;
2:
CopySpatialCalibration;
3:
CopyDensityCalibration;
end; {case}
end;
WhatToUndo := NothingToUndo;
end;
procedure DoArithmetic (MenuItem: integer; constant: extended);
var
table: LookupTable;
i: integer;
tmp: LongInt;
LogScale: extended;
Canceled: boolean;
begin
canceled := false;
if not macro then
case menuItem of
AddItem:
constant := GetReal('Constant to add:', 25, Canceled);
SubtractItem:
constant := GetReal('Constant to subtract:', 25, Canceled);
MultiplyItem: begin
constant := GetReal('Constant to multiply by:', 1.25, Canceled);
if constant < 0.0 then begin
PutMessage('Constant must be positive.');
exit(DoArithmetic);
end;
end;
DivideItem: begin
constant := GetReal('Constant to divide by:', 1.25, Canceled);
if constant <= 0.0 then begin
PutMessage('Constant must be nonzero and positive.');
exit(DoArithmetic);
end;
end;
LogItem: begin
constant := 0.0;
LogScale := 255.0 / ln(255.0);
end;
end; {case}
if Canceled then
exit(DoArithmetic);
for i := 0 to 255 do begin
case MenuItem of
AddItem:
tmp := round(i + constant);
SubtractItem:
tmp := round(i - constant);
MultiplyItem:
tmp := round(i * constant);
DivideItem:
tmp := round(i / constant);
LogItem:
if i = 0 then
tmp := 0
else
tmp := round(ln(i) * LogScale);
end;
if tmp < 0 then
tmp := 0;
if tmp > 255 then
tmp := 255;
table[i] := tmp;
end;
ApplyTable(table);
end;
procedure AutoThreshold;
{Iterative thresholding technique, described originally by Ridler & Calvard in}
{"PIcture Thresholding Using an Iterative Selection Method", IEEE transactions}
{ on Systems, Man and Cybernetics, August, 1978. }
var
AutoSelectAll, SaveRedirectFlag: boolean;
index, MovingIndex, level: integer;
tempSum1, tempSum2, tempSum3, tempSum4, result: extended;
begin
AutoSelectAll := not info^.RoiShowing;
if AutoSelectAll then
SelectAll(false);
SaveRedirectFlag := RedirectSampling;
RedirectSampling := false;
if info^.RoiType = RectRoi then
GetRectHistogram
else
GetHistogram;
RedirectSampling := SaveRedirectFlag;
OptionKeyWasDown := OptionKeyDown;
if not OptionKeyWasDown then begin
{Default is to set to these to null so erased areas won't be included in the threshold }
Histogram[0] := 0;
Histogram[255] := 0;
end;
with Results do begin {From ComputeResults}
MinIndex := 0;
while (histogram[MinIndex] = 0) and (MinIndex < 255) do
MinIndex := MinIndex + 1;
MaxIndex := 255;
while (histogram[MaxIndex] = 0) and (MaxIndex > 0) do
MaxIndex := MaxIndex - 1;
if (MinIndex >= MaxIndex) then begin
level := 128;
ShowMessage(concat('Threshold=', Long2Str(level)));
EnableThresholding(level);
exit(AutoThreshold);
end;
MovingIndex := MinIndex;
repeat
tempSum1 := 0;
tempSum2 := 0;
tempSum3 := 0;
tempSum4 := 0;
for index := MinIndex to MovingIndex do begin
tempSum1 := tempSum1 + index * Histogram[index];
tempSum2 := tempSum2 + Histogram[index];
end;
for index := (MovingIndex + 1) to MaxIndex do begin
tempSum3 := tempSum3 + index * Histogram[index];
tempSum4 := tempSum4 + Histogram[index];
end;
Result := (tempSum1 / TempSum2 / 2) + (tempSum3 / tempSum4 / 2);
MovingIndex := MovingIndex + 1;
until ((MovingIndex + 1) > result) or (MovingIndex > (MaxIndex - 1));
level := Round(result);
EnableThresholding(level);
ShowMessage(concat('Threshold=', Long2Str(level)));
end; {with}
end;
procedure AutoDensitySlice;
var
AutoSelectAll: boolean;
sigmak1k2, sigmax, nsum: real;
i, j, maxk1, maxk2, temp: integer;
musubt, omegak1, omegak2, muk1, muk2: real;
part1, part2, part3: real;
intermed1, intermed2, intermed3: real;
begin
ResetGrayMap;
AutoSelectAll := not info^.RoiShowing;
if AutoSelectAll then
SelectAll(false);
if info^.RoiType = RectRoi then
GetRectHistogram
else
GetHistogram;
maxk1 := 0;
maxk2 := 0;
musubt := 0.0;
nsum := 0.0;
for i := 1 to 254 do begin
nsum := nsum + histogram[i];
end;
for i := 1 to 254 do begin
musubt := musubt + (i * (histogram[i] / nsum));
end;
sigmak1k2 := 0.0;
sigmax := 0.0;
omegak1 := 0.0;
muk1 := 0.0;
for i := 1 to 253 do begin
temp := i + 1;
omegak2 := 0.0;
muk2 := 0.0;
omegak1 := omegak1 + (histogram[i] / nsum);
muk1 := muk1 + (i * (histogram[i] / nsum));
if omegak1 > 0.0 then begin
for j := temp to 254 do begin
omegak2 := omegak2 + (histogram[j] / nsum);
muk2 := muk2 + (j * (histogram[j] / nsum));
if omegak1 * omegak2 * (1.0 - omegak1 - omegak2) > 0.0 then begin
part1 := ((omegak1 * muk2) - (omegak2 * muk1)) * ((omegak1 * muk2) - (omegak2 * muk1));
intermed1 := omegak2 * omegak1;
part2 := ((omegak1 * (musubt - muk2)) - (muk1 * (1 - omegak2))) * ((omegak1 * (musubt - muk2)) - (muk1 * (1 - omegak2)));
intermed2 := omegak1 * (1 - omegak1 - omegak2);
part3 := ((omegak2 * (musubt - muk1)) - (muk2 * (1 - omegak1))) * ((omegak2 * (musubt - muk1)) - (muk2 * (1 - omegak1)));
intermed3 := omegak2 * (1 - omegak1 - omegak2);
if intermed1 * intermed2 * intermed3 > 0.0 then begin
sigmak1k2 := part1 / intermed1 + part2 / intermed2 + part3 / intermed3;
end;
end;
if sigmak1k2 > sigmax then begin
maxk1 := i;
maxk2 := j;
sigmax := sigmak1k2;
end;
end;
end;
end;
SliceStart := maxk1;
SliceEnd := maxk2;
end;
procedure FixColors;
{Because Image always sets LUT entries 0 and 255 to white and black respectively we need to map}
{pixels with values of 0 or 255 to the nearest matching color in the other 254 LUT entries.}
var
i, index2, match0, match255: integer;
table: LookupTable;
procedure BestMatch (index1: integer; var match: integer);
var
i: integer;
rdiff, gdiff, bdiff: LongInt;
diff, mindiff: extended;
begin
match := index1;
mindiff := 10e10;
if index1 = 0 then
index2 := 1
else
index2 := 254;
with info^ do
for i := 1 to 254 do begin
rdiff := bsr(cTable[index1].rgb.red, 8) - bsr(cTable[index2].rgb.red, 8);
gdiff := bsr(cTable[index1].rgb.green, 8) - bsr(cTable[index2].rgb.green, 8);
bdiff := bsr(cTable[index1].rgb.blue, 8) - bsr(cTable[index2].rgb.blue, 8);
diff := sqrt(sqr(rdiff) + sqr(gdiff) + sqr(bdiff));
if diff < mindiff then begin
match := index2;
mindiff := diff;
end;
if index1 = 0 then
index2 := index2 + 1
else
index2 := index2 - 1;
end;
end;
begin
BestMatch(0, match0);
BestMatch(255, match255);
table[0] := match0;
for i := 1 to 254 do
table[i] := i;
table[255] := match255;
ApplyTable(table);
end;
procedure GetDItemRect (d: DialogPtr; item: integer; var r: rect);
var
iType: integer;
ignore: handle;
begin
GetDItem(d, item, itype, ignore, r)
end;
procedure DrawPopUpText (str: str255; r: rect);
begin
TextFont(SystemFont);
if (str = '+') or (str = '–') or (str = '÷') then begin
TextSize(24);
MoveTo(r.left + 13, r.bottom - 2);
end
else begin
TextSize(12);
MoveTo(r.left + 13, r.bottom - 5);
end;
DrawString(str);
end;
procedure ImageMathUProc (d: DialogPtr; item: integer);
{User proc for Image Math dialog box}
var
str: str255;
VersInfo: str255;
r: rect;
begin
SetPort(d);
GetDItemRect(d, item, r);
DrawDropBox(r);
case item of
OpItem: begin
GetItem(ImageMathOpsMenuH, ord(CurrentMathOp) + 1, str);
DrawPopUpText(str, r);
end;
end;
end;
procedure SetUProc (d: DialogPtr; item: integer; pptr: handle);
var
itype: integer;
r: rect;
h: handle;
begin
GetDItem(d, item, itype, h, r);
SetDItem(d, item, itype, pptr, r);
end;
procedure DoImageMath;
const
ScaleItem = 10;
OffsetItem = 11;
ResultItem = 12;
var
d: DialogPtr;
item, i, MenuItem: integer;
r: rect;
str: str255;
begin
InitCursor;
d := GetNewDialog(200, nil, pointer(-1));
SetUProc(d, Src1Item, @ImageMathUProc);
SetUProc(d, Src2Item, @ImageMathUProc);
SetUProc(d, OpItem, @ImageMathUProc);
repeat
if item = OpItem then begin
setport(d);
GetDItemRect(d, item, r);
MenuItem := PopUpMenu(ImageMathOpsMenuH, r.left, r.top, ord(CurrentMathOp) + 1);
case MenuItem of
1:
CurrentMathOp := AddMath;
2:
CurrentMathOp := SubMath;
3:
CurrentMathOp := MulMath;
4:
CurrentMathOp := DivMath;
5:
CurrentMathOp := AndMath;
6:
CurrentMathOp := OrMath;
7:
CurrentMathOp := XorMath;
8:
CurrentMathOp := MaxMath;
9:
CurrentMathOp := MinMath;
10:
CurrentMathOp := CopyMath;
end;
DrawDropBox(r);
GetItem(ImageMathOpsMenuH, ord(CurrentMathOp) + 1, str);
DrawPopUpText(str, r);
end;
ModalDialog(nil, item);
until (item = ok) or (item = cancel);
DisposDialog(d);
if item = cancel then
exit(DoImageMath);
end;
end.